package com.bobo.web.provider.filter;

import com.alibaba.fastjson.JSON;
import com.bobo.web.api.domain.WxUserDO;
import com.bobo.web.api.vo.base.ResponseResult;
import com.bobo.web.provider.util.RedisUtils;
import com.bobo.web.provider.util.VoteRedisUtils;
import com.bobo.web.provider.util.commutils.JsonUtils;
import com.bobo.web.provider.controller.wechat.WeChatController;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Map;

/**
 * WebContext
 * 通过ThreadLocal保存当前登录用户的信息
 *
 * @author:v
 * @version:1.0
 * @date:2017/9/11
 */
@WebFilter(urlPatterns = "/*")
public class AuthenticateFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticateFilter.class);

    @Resource
    private RedisUtils redisUtils;
    @Resource
    private VoteRedisUtils voteRedisUtils;
    @Value("${basketball.isTest}")
    private Boolean isTest;
    @Value("${basketball.visit.count}")
    private int visitCount;

    @Resource
    private WeChatController weChatController;

    private static final String INTERNAL_PATH = "/basketball/api/wechat";
    private static final String PAY_PATH = "/basketball/api/order/weChatPayCallBack";
    private static final int INVALID_TOKEN_CODE = 1;
    private static final String ACTIVITY_ID = "activityId";


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        try {

            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) resp;
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Credentials", "true");
            response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, content-type, accept, origin, authorization, x-csrftoken");
            response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
            response.setHeader("Content-type", "application/json;charset=UTF-8");
            String path = request.getRequestURI();
            String queryString = request.getQueryString();
            if (StringUtils.isBlank(path)) {
                ResponseResult<String> result = new ResponseResult<>();
                result.setCode(INVALID_TOKEN_CODE);
                result.setMessage("Please visit the exact link!");
                resp.getWriter().write(JSON.toJSONString(result));
                return;
            }
            LOGGER.info("request path={},queryString={}", path, queryString);
            Long activityId = null;
            String ac = request.getParameter(ACTIVITY_ID);
            if (NumberUtils.isDigits(ac)) {
                activityId = Long.parseLong(request.getParameter(ACTIVITY_ID));
            }
            if ("POST".equalsIgnoreCase(request.getMethod()) && activityId == null) {
                ServletRequest requestWrapper = new RequestReaderHttpServletRequestWrapper(request);
                String bodyString = getBodyString(requestWrapper.getReader());
                Map map = JsonUtils.toBean(bodyString, Map.class);
                if (map != null && map.get(ACTIVITY_ID) != null) {
                    activityId = Long.parseLong(String.valueOf(map.get(ACTIVITY_ID)));
                }
                req = requestWrapper;
            }
            //如果想跳过验证 带上overAuth=1
            if (StringUtils.isNotEmpty(path)) {
                if (path.startsWith(INTERNAL_PATH) || path.startsWith(PAY_PATH)) {
                    chain.doFilter(req, resp);
                    return;
                }
                if (path.startsWith("/actuator")) {
                    chain.doFilter(req, resp);
                    return;
                }
                //获取某个参数 判断值
                String overAuth = request.getParameter("overAuth");
                if (StringUtils.isNotBlank(overAuth) && String.valueOf(INVALID_TOKEN_CODE).equals(overAuth)) {
                    chain.doFilter(req, resp);
                    return;
                }
            }
            //判断cookie中是否有openid，没有则转向获取openid的url
            Cookie[] cookies = request.getCookies();
            String openId = null;
            // 判断cookie中是否存在openid 若存在则直接跳过，不存在则获取一次
            if (cookies != null) {
                for (Cookie cookie : cookies) {
                    if (cookie.getName().equals("openId")) {
                        openId = cookie.getValue();
                    }
                }
            }
            if (isTest) {
                openId = "test";
            }else {
                // TODO 暂时不需要openID
                chain.doFilter(req, resp);
                return;
            }
            if (StringUtils.isEmpty(openId)) {
                resp.getWriter().write(JSON.toJSONString(ResponseResult.error("用户openID未获取到")));
                return;
            }
            //保存登录信息 当前线程
            //保存当前登录人的信息到当前线程
            //WxUserDO userDO = userManagerService.getUserByOpenId(openId);
            WxUserDO userDO = new WxUserDO();
            if (userDO == null) {
                if (StringUtils.isNotEmpty(queryString)) {
                    path = path + "?" + queryString;
                }
                return;
            }
            //接口过载保护
            Integer limitNum = voteRedisUtils.getLimitNum(path, 1, 60);
            if (limitNum != null && limitNum > visitCount) {
                LOGGER.error("request path" + path + "超过了请求次数！");
                resp.getWriter().write(JSON.toJSONString(ResponseResult.error("聚焦活动的人太多,正在排队...请稍后再试哦")));
                return;
            }
            WebContext.setUserContext(userDO);
            chain.doFilter(req, resp);
            WebContext.clearUserContext();
        } catch (Exception e) {
            LOGGER.error("设置Response Header 时出错，error message = {}", e);
        }
    }

    @Override
    public void destroy() {
        LOGGER.info("===================destroy===============");
        WebContext.clearUserContext();
    }

    //获取request请求body中参数
    public static String getBodyString(BufferedReader br) {
        String inputLine;
        String str = "";
        try {
            while ((inputLine = br.readLine()) != null) {
                str += inputLine;
            }
            br.close();
        } catch (IOException e) {
            LOGGER.error("IOException: ", e);
        }
        return str;
    }
}
